package com.example.distributed.locks.aspects;

import com.example.distributed.locks.annotations.RedisLock;
import com.example.distributed.locks.common.SpELUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * @author 谢汉冰
 * @Title: RedisLockAspect
 * @Package com.example.distributed.locks.aspects
 * @date 2023/10/23 14:42
 * @description: redis锁的切面
 */

@Aspect
@Component
@Slf4j
@SuppressWarnings("unused")
public class RedisLockAspect {

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@Pointcut("@annotation(com.example.distributed.locks.annotations.RedisLock)")
	public void pointcutExecute() {

	}


	@Around("pointcutExecute()")
	public Object redisLock(ProceedingJoinPoint joinPoint)
	{
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();


		RedisLock redisLockAnnotation = method.getAnnotation(RedisLock.class);
		// redisLockAnnotation.n
		String lockName = redisLockAnnotation.name();
		if (lockName.isEmpty()) {
			lockName = method.getDeclaringClass() + "." + method.getName();
		}

		try {
			BoundValueOperations<String, String> lock = redisTemplate.boundValueOps(lockName);


			if (lock.setIfAbsent("wpy")) {
				log.debug("获取锁：[{}]成功", lockName);
				lock.expire(redisLockAnnotation.timeOut(), TimeUnit.SECONDS);

				Object result = joinPoint.proceed();
				if (redisLockAnnotation.afterExecuteRelease()) {
					redisTemplate.delete(lockName);
					log.debug("释放锁:[{}]成功", lockName);
				}
				return result;

			} else {
				log.info("线程未竞争到锁：[{}],方法未执行:{}", lockName, method.getDeclaringClass() + "." + method.getName());
			}

		} catch (Throwable e) {
			redisTemplate.delete(lockName);
			log.error(e.getMessage());
		}
		return null;
	}
}
